Blockly.defineBlocksWithJsonArray([
  {
    type: 'ast_AttributeFull',
    lastDummyAlign0: 'RIGHT',
    message0: '%1 . %2',
    args0: [
      { type: 'input_value', name: 'VALUE' },
      { type: 'field_input', name: 'ATTR', text: 'default' }
    ],
    inputsInline: true,
    output: null
  }
])

Blockly.defineBlocksWithJsonArray([
  {
    type: 'ast_Attribute',
    message0: '%1 . %2',
    args0: [
      { type: 'field_variable', name: 'VALUE', variable: 'variable' },
      { type: 'field_input', name: 'ATTR', text: 'attribute' }
    ],
    inputsInline: true,
    output: null
  }
])

Blockly.Python.ast_Attribute = function (block) {
  // Text value.
  const value = Blockly.Python.variableDB_.getName(
    block.getFieldValue('VALUE'),
    Blockly.Variables.NAME_TYPE
  )
  const attr = block.getFieldValue('ATTR')
  const code = value + '.' + attr
  return [code, Blockly.Python.ORDER_MEMBER]
}

Blockly.Python.ast_AttributeFull = function (block) {
  // Text value.
  const value =
    Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) ||
    Blockly.Python.blank
  const attr = block.getFieldValue('ATTR')
  const code = value + '.' + attr
  return [code, Blockly.Python.ORDER_MEMBER]
}

Blockly.Blocks.function_attr = {
  init: function () {
    this.appendDummyInput().appendField(new Blockly.FieldTextInput('lib'), 'lib_name')
    this.appendDummyInput().appendField('.').appendField(new Blockly.FieldTextInput('func'), 'func_name')
    this.setHelpUrl()
    this.setColour(230)
    this.itemCount_ = 3
    this.updateShape_()
    this.setOutput(true, null)
    this.setMutator(new Blockly.Mutator(['attr_create_with_item']))
    this.setTooltip('function_attr')
  },
  updateShape_: function () {
    if (this.itemCount_ && this.getInput('EMPTY')) {
      this.removeInput('EMPTY')
    } else if (!this.itemCount_ && !this.getInput('EMPTY')) {
      this.appendDummyInput('EMPTY').appendField('lambda')
    }
    // Add new inputs.
    for (let k = 0; k < this.itemCount_; k++) {
      if (!this.getInput('ADD' + k)) {
        const input = this.appendValueInput('ADD' + k).setAlign(
          Blockly.ALIGN_RIGHT
        )
        if (k === 0) {
          input.appendField('')
        }
      }
    }
    let addElement = this.itemCount_
    while (this.getInput('ADD' + addElement)) {
      this.removeInput('ADD' + addElement)
      addElement++
    }
  },

  mutationToDom: function () {
    const containerCreated = Blockly.utils.xml.createElement('mutation')
    containerCreated.setAttribute('items', this.itemCount_)
    return containerCreated
  },

  domToMutation: function (xmlElement) {
    this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10)
    this.updateShape_()
  },

  compose: function (containerBlock) {
    let itemToBlock = containerBlock.getInputTargetBlock('STACK')
    const connectedArray = []
    while (itemToBlock && !itemToBlock.isInsertionMarker()) {
      connectedArray.push(itemToBlock.valueConnection_)
      itemToBlock =
        itemToBlock.nextConnection && itemToBlock.nextConnection.targetBlock()
    }
    let i = 0
    while (i < this.itemCount_) {
      const connection = this.getInput('ADD' + i).connection.targetConnection
      if (connection && connectedArray.indexOf(connection) === -1) {
        connection.disconnect()
      }
      i++
    }
    this.itemCount_ = connectedArray.length
    this.updateShape_()
    let j = 0
    while (j < this.itemCount_) {
      Blockly.Mutator.reconnect(connectedArray[j], this, 'ADD' + j)
      j++
    }
  },
  decompose: function (workspace) {
    const container = workspace.newBlock('attr_create_with_container')
    container.initSvg()
    let connection = container.getInput('STACK').connection
    for (let i = 0; i < this.itemCount_; i++) {
      const itemBlock = workspace.newBlock('attr_create_with_item')
      itemBlock.initSvg()
      connection.connect(itemBlock.previousConnection)
      connection = itemBlock.nextConnection
    }
    return container
  },

  saveConnections: function (containerBlock) {
    let itemBlock = containerBlock.getInputTargetBlock('STACK')
    let index = 0
    while (itemBlock) {
      const inputElement = this.getInput('ADD' + index)
      itemBlock.valueConnection_ = inputElement && inputElement.connection.targetConnection
      index++
      itemBlock =
        itemBlock.nextConnection && itemBlock.nextConnection.targetBlock()
    }
  }
}

Blockly.Blocks.attr_create_with_container = {
  init: function () {
    this.setStyle('list_blocks')
    this.appendDummyInput().appendField('add argument')
    this.appendStatementInput('STACK')
    this.setTooltip('add argument')
    this.contextMenu = false
  }
}

Blockly.Blocks.attr_create_with_item = {
  init: function () {
    this.setStyle('list_blocks')
    this.appendDummyInput().appendField('argument')
    this.setPreviousStatement(true)
    this.setNextStatement(true)
    this.setTooltip('lambda')
    this.contextMenu = false
    this.setColour(230)
  }
}

Blockly.Python.function_attr = function (block) {
  const lib = block.getFieldValue('lib_name')
  const func = block.getFieldValue('func_name')
  const elements = new Array(block.itemCount_)
  for (let i = 0; i < block.itemCount_; i++) {
    elements[i] =
      Blockly.Python.valueToCode(block, 'ADD' + i, Blockly.Python.ORDER_NONE) ||
      'None'
  }
  const code = lib + '.' + func + '(' + elements.join(', ') + ')'
  return [code, Blockly.Python.ORDER_NONE]
}
